package com.zy.openchat.util;

import com.zy.openchat.core.model.setting.XFTransferInfo;
import com.blankj.utilcode.util.GsonUtils;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.iflytek.cloud.Setting;
import com.ja.openchat.BuildConfig;
import com.zy.openchat.core.model.file.ApiResultDto;
import com.zy.openchat.core.model.setting.XFJsonParse;
import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.SignatureException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;

public class SpeechRecognizerUtil {

    private volatile static SpeechRecognizerUtil instance;
    private static String APPID = BuildConfig.XF_APPID;
    private static String APISecret = BuildConfig.XF_APISecret;
    private static String APIKey = BuildConfig.XF_APIKey;
    private static String SECRET_KEY = BuildConfig.XF_SecretKey;
    private SpeechRecognizerUtil() {

    }

    public void init(){
        Setting.setShowLog(true);
    }


    public Observable<String> recognizer(final String localAudioPath){
        return Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                File audio = new File(localAudioPath);
                try {
                    FileInputStream fis = new FileInputStream(audio);
                    try {
                        String taskId = prepare(audio);
                        byte[] slice = new byte[10485760];

                        int len;
                        for(SliceIdGenerator generator = new SliceIdGenerator(); (len = fis.read(slice)) > 0; uploadSlice(taskId, generator.getNextSliceId(), slice)) {
                            if (fis.available() == 0) {
                                slice = Arrays.copyOfRange(slice, 0, len);
                            }
                        }
                        merge(taskId);

                        while(true) {
                            ApiResultDto taskProgress = getProgress(taskId);
                            if (taskProgress.getOk() == 0) {
                                if (taskProgress.getErr_no() != 0) {
                                    emitter.onError(new Throwable(GsonUtils.toJson(taskProgress)));
                                }

                                String taskStatus = taskProgress.getData();
                                if (GsonUtils.fromJson(taskStatus,JsonObject.class).get("status").getAsInt() == 9) {
                                    emitter.onNext(getResult(taskId));
                                    emitter.onComplete();
                                    break;
                                }
                            } else {
                                emitter.onError(new Throwable("获取任务进度失败！"));
                                emitter.onComplete();
                            }
                        }
                    } finally {
                        if (fis != null) {
                            fis.close();
                        }

                    }
                } catch (Exception var26) {
                    emitter.onError(var26);
                    emitter.onComplete();
                }
            }
        });

    }


    public static Map<String, String> getBaseAuthParam(String taskId) throws SignatureException {
        Map<String, String> baseParam = new HashMap();
        String ts = String.valueOf(java.lang.System.currentTimeMillis() / 1000L);
        baseParam.put("app_id", APPID);
        baseParam.put("ts", ts);
        baseParam.put("signa", EncryptUtil.HmacSHA1Encrypt(EncryptUtil.MD5(APPID + ts), SECRET_KEY));
        if (taskId != null) {
            baseParam.put("task_id", taskId);
        }

        return baseParam;
    }

    private String prepare(File audio) throws SignatureException {
        Map<String, String> prepareParam = getBaseAuthParam((String)null);
        long fileLenth = audio.length();
        prepareParam.put("file_len", String.valueOf(fileLenth));
        prepareParam.put("file_name", audio.getName()+".wav");
        prepareParam.put("slice_num", String.valueOf(fileLenth / 10485760L + (long)(fileLenth % 10485760L == 0L ? 0 : 1)));
        String response = OkHttpUtil.getInstance().postData("http://raasr.xfyun.cn/api/prepare", prepareParam);
        if (response == null) {
            throw new RuntimeException("预处理接口请求失败！");
        } else {
            ApiResultDto resultDto = (ApiResultDto)GsonUtils.fromJson(response, ApiResultDto.class);
            String taskId = resultDto.getData();
            if (resultDto.getOk() == 0 && taskId != null) {
                return taskId;
            } else {
                throw new RuntimeException("预处理失败！" + resultDto.getFailed());
            }
        }
    }

    private void uploadSlice(String taskId, String sliceId, byte[] slice) throws SignatureException {
        Map<String, String> uploadParam = getBaseAuthParam(taskId);
        uploadParam.put("slice_id", sliceId);
        String response = OkHttpUtil.getInstance().postMulti("http://raasr.xfyun.cn/api/upload", uploadParam, slice);
        if (response == null) {
            throw new RuntimeException("分片上传接口请求失败！");
        } else if (GsonUtils.fromJson(response,JsonObject.class).get("ok").getAsInt() == 0) {
        } else {
            throw new RuntimeException("分片上传失败！" + response + "|" + taskId);
        }
    }

    private void merge(String taskId) throws SignatureException {
        String response = OkHttpUtil.getInstance().postData("http://raasr.xfyun.cn/api/merge", getBaseAuthParam(taskId));
        if (response == null) {
            throw new RuntimeException("文件合并接口请求失败！");
        } else if (GsonUtils.fromJson(response,JsonObject.class).get("ok").getAsInt() == 0) {
        } else {
            throw new RuntimeException("文件合并失败！" + response);
        }
    }

    private ApiResultDto getProgress(String taskId) throws SignatureException {
        String response = OkHttpUtil.getInstance().postData("http://raasr.xfyun.cn/api/getProgress", getBaseAuthParam(taskId));
        if (response == null) {
            throw new RuntimeException("获取任务进度接口请求失败！");
        } else {
            return (ApiResultDto)GsonUtils.fromJson(response, ApiResultDto.class);
        }
    }

    private String getResult(String taskId) throws SignatureException {
        String responseStr = OkHttpUtil.getInstance().postData("http://raasr.xfyun.cn/api/getResult", getBaseAuthParam(taskId));
        if (responseStr == null) {
            throw new RuntimeException("获取结果接口请求失败！");
        } else {
            ApiResultDto response = (ApiResultDto)GsonUtils.fromJson(responseStr, ApiResultDto.class);
            if (response.getOk() != 0) {
                throw new RuntimeException("获取结果失败！" + responseStr);
            } else {
                List<XFTransferInfo> xfTransferInfos = GsonUtils.fromJson(response.getData(),new TypeToken<List<XFTransferInfo>>(){}.getType());
                StringBuilder stringBuilder = new StringBuilder();
                for(XFTransferInfo info:xfTransferInfos){
                    stringBuilder.append(info.onebest);
                }
                return stringBuilder.toString();
            }
        }
    }

    public Observable<String> translation(final String text) {
        return Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                String resp = OkHttpUtil.getInstance().postJson(buildRequetUrl(),buildParam(text));
                XFJsonParse myJsonParse = GsonUtils.fromJson(resp, XFJsonParse.class);
                String textBase64Decode=new String(Base64.getDecoder().decode(myJsonParse.payload.result.text));
                JsonObject jsonObject = GsonUtils.fromJson(textBase64Decode,JsonObject.class);
                String result =  text;
                if(jsonObject.get("trans_result").isJsonObject()){
                    JsonObject trans_result = jsonObject.getAsJsonObject("trans_result");
                    if(trans_result.has("dst")){
                        result = trans_result.get("dst").getAsString();
                    }
                }
                emitter.onNext(result);
                emitter.onComplete();
            }
        });
    }
    private static final String requestUrl = "https://itrans.xf-yun.com/v1/its";
    private static final String RES_ID = "its_en_cn_word";
    private static String FROM="en";// 源语种
    private static String TO="cn";// 目标语种
    private String buildRequetUrl(){
        URL url = null;
        // 替换调schema前缀 ，原因是URL库不支持解析包含ws,wss schema的url
        String  httpRequestUrl = requestUrl.replace("ws://", "http://").replace("wss://","https://" );
        try {
            url = new URL(httpRequestUrl);
            //获取当前日期并格式化
            SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
            format.setTimeZone(TimeZone.getTimeZone("GMT"));
            String date = format.format(new Date());
            String host = url.getHost();
            StringBuilder builder = new StringBuilder("host: ").append(host).append("\n").//
                    append("date: ").append(date).append("\n").//
                    append("POST ").append(url.getPath()).append(" HTTP/1.1");
            Charset charset = Charset.forName("UTF-8");
            Mac mac = Mac.getInstance("hmacsha256");
            SecretKeySpec spec = new SecretKeySpec(APISecret.getBytes(charset), "hmacsha256");
            mac.init(spec);
            byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));
            String sha = Base64.getEncoder().encodeToString(hexDigits);
            String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", APIKey, "hmac-sha256", "host date request-line", sha);
            String authBase = Base64.getEncoder().encodeToString(authorization.getBytes(charset));
            return String.format("%s?authorization=%s&host=%s&date=%s", requestUrl, URLEncoder.encode(authBase), URLEncoder.encode(host), URLEncoder.encode(date));
        } catch (Exception e) {
            throw new RuntimeException("assemble requestUrl error:"+e.getMessage());
        }
    }

    private String  buildParam(String text) {
        String param = "{"+
                "    \"header\": {"+
                "        \"app_id\": \""+APPID+"\","+
                "        \"status\": 3,"+
                "        \"res_id\": \""+RES_ID+"\""+
                "    },"+
                "    \"parameter\": {"+
                "        \"its\": {"+
                "            \"from\": \""+FROM+"\","+
                "            \"to\": \""+TO+"\","+
                "            \"result\": {}"+
                "        }"+
                "    },"+
                "    \"payload\": {"+
                "        \"input_data\": {"+
                "            \"encoding\": \"utf8\","+
                "            \"status\": 3,"+
                "            \"text\": \""+Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8))+"\""+
                "        }"+
                "    }"+
                "}";
        return param;
    }

    public static SpeechRecognizerUtil getInstance() {
        if (instance == null) {
            synchronized (SpeechRecognizerUtil.class) {
                if (instance == null) {
                    instance = new SpeechRecognizerUtil();
                }
            }
        }
        return instance;
    }

}
